package org.nox.helloseries.web.client;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.nox.helloseries.web.client.metier.Application;
import org.nox.helloseries.web.client.metier.SerieWeb;
import org.nox.helloseries.web.client.metier.VersionWeb;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class Main implements EntryPoint
{
    /**
     * Create a remote service proxy to talk to the server-side Greeting service.
     */
    private final HelloSeriesServiceAsync helloSeriesWebService = GWT.create( HelloSeriesService.class );

    private FlexTable flexTable;

    private HorizontalPanel panelAjout;

    private ArrayList<SerieWeb> series;

    private VerticalPanel mainPanel;

    private VerticalPanel panelStatut;

    private SimplePanel waitingPanel;

    private Label errorBox;

	private HTML help;

    /**
     * This is the entry point method.
     */
    public void onModuleLoad()
    {
        System.out.println( "[MAIN] Initialisation de la page" );

        // Création des objets
        errorBox = new Label();

        // Création du panel principal
        createMainPanel();

        // Création message aide
        createHelpText();

        // Bloc de statut
        createBlocStatut();
        
        // Création tableau séries
        createTableauSeries();

        // Bloc d'ajout de séries
        panelAjout = new HorizontalPanel();

        // Création de l'overlay
        waitingPanel = new SimplePanel();
        waitingPanel.setStyleName( "waitingPanel" );

        initStatutsServer();

        recupererSeries();

        RootPanel.get("mainPanel").add( mainPanel );
        RootPanel.get("waitingPanel").add( waitingPanel );
        RootPanel.get().setStyleName( "body" );
    }

    private void createHelpText() {
    	// Over moche :)
    	StringBuilder message = new StringBuilder();
    	message.append("HelloSeries est un ensemble d'applications permettant de télécharger automatiquement toutes les séries que vous voulez. Cette interface permet de configurer quelles séries sont à télécharger.");
    	message.append("<br/>");
    	message.append("La configuration doit être remplie par rapport au dernier épisode vu/possédé (épisode 0 si aucuns vus)");
    	message.append("<br/>");
    	message.append("<br/>");
    	message.append("<u>Exemple</u> : si j'attends l'épisode 13 de la série Lost. Je configure pour la série Lost l'épisode 12 de la même saison.");
    	message.append("<br/>");
    	message.append("<br/>");
    	message.append("Une fois configuré, HelloSeries se chargera de mettre à jour sa configuration suivant ce qu'il trouve et ne s'arrêtera pas avant d'avoir atteint le dernier épisode disponible (de la saison en cours ou d'une supérieure) et ainsi, téléchargera tous les épisodes manquants disponibles dans les sources utilisées.");
    	help = new HTML(message.toString());
    	help.setStyleName("help");
    	help.setVisible(false);
    	mainPanel.add(help);	
	}

	private void initStatutsServer()
    {
        helloSeriesWebService.getStatutsHelloSeries( new AsyncCallback<Map<Application, Boolean>>()
        {

            @Override
            public void onFailure( Throwable caught )
            {

            }

            @Override
            public void onSuccess( Map<Application, Boolean> result )
            {
                panelStatut.clear();

                for ( Entry<Application, Boolean> entry : result.entrySet() )
                {
                    // Bloc d'ajout de séries
                    HorizontalPanel ligneStatut = new HorizontalPanel();
                    // Nom de l'application
                    Label application = new Label( entry.getKey().getValue() );
                    application.setStyleName( "labelApplication" );
                    ligneStatut.add( application );
                    if ( entry.getValue() != null && entry.getValue() )
                    {
                        ligneStatut.add( new Image( "images/statusok.png" ) );
                    }
                    else
                    {
                        ligneStatut.add( new Image( "images/statusko.png" ) );
                    }
                    panelStatut.add( ligneStatut );
                }
            }

        } );
    }

    private void createTableauSeries()
    {
        flexTable = new FlexTable();
        flexTable.setStyleName( "flexTable" );
        mainPanel.add( flexTable );
    }

    private void createMainPanel()
    {
        mainPanel = new VerticalPanel();
        mainPanel.setStyleName( "mainPanel" );
        mainPanel.add( new Image( "images/logo.png" ) );
    }

    private void createBlocStatut()
    {
        // titre du panel
        Label titrePanelStatut = new Label( "Statuts des applications Helloseries" );
        titrePanelStatut.setStyleName( "titrePanelStatut" );
        mainPanel.add( titrePanelStatut );
        // panel de statut
        panelStatut = new VerticalPanel();
        panelStatut.setStyleName( "panelStatut" );
        mainPanel.add( panelStatut );
    }

    private void recupererSeries()
    {
        helloSeriesWebService.getData( new AsyncCallback<List<SerieWeb>>()
        {
            @Override
            public void onSuccess( List<SerieWeb> result )
            {
            	help.setVisible(true);

            	System.out.println( "[MAIN] Call RPC Service getData() Successfull : " + result.size() + " series" );
                flexTable.setText( 0, 0, "Active" );
                flexTable.setText( 0, 1, "Nom" );
                flexTable.setText( 0, 2, "Saison" );
                flexTable.setText( 0, 3, "Episode" );
                flexTable.setText( 0, 4, "HD" );
                flexTable.setText( 0, 5, "Langue" );
                flexTable.setText( 0, 6, "Action" );
                flexTable.setTitle( "HelloSeries WebConf" );
                flexTable.getRowFormatter().addStyleName( 0, "flexTableHeader" );

                doFillFlexTable( result );
                createZoneAjout();
                hideWaitingScreen();
            }

            @Override
            public void onFailure( Throwable caught )
            {
            	help.setVisible(false);
                System.out.println( "[MAIN] Call RPC Service getData() Fail : " + caught.getMessage() );
                showError( caught );
                hideWaitingScreen();
            }
        } );
    }

    private void showError( Throwable caught )
    {
        errorBox.setStyleName( "errorBox" );
        errorBox.setText( "Erreur lors de la récupération des données de Hello Series : " + caught.getMessage() );
        mainPanel.add( errorBox );
        GWT.log( "Failure : " + caught.getMessage() );
        ;
    }

    protected void doFillFlexTable( List<SerieWeb> result )
    {
        series = new ArrayList<SerieWeb>();
        series.addAll( result );

        int row = 1;
        for ( SerieWeb serie : result )
        {
            addSerie( row, serie );
            row++;
        }
    }

    private void refreshFlexTable()
    {
        doFillFlexTable( series );
        for ( int row = 0; row < flexTable.getRowCount(); row++ )
        {
            flexTable.getRowFormatter().removeStyleName( row, "flexTableAdded" );
        }
    }

    private void createZoneAjout()
    {

        // Ligne d'ajout
        Label titreAjout = new Label( "Ajouter une série" );
        titreAjout.setStyleName( "titreAjout" );
        mainPanel.add( titreAjout );

        // Case Nom
        final TextBox nom = new TextBox();
        panelAjout.add( nom );
        // Case saison
        final TextBox saison = new TextBox();
        panelAjout.add( saison );
        // Case episode
        final TextBox episode = new TextBox();
        panelAjout.add( episode );
        // Case HD
        final CheckBox hd = new CheckBox();
        panelAjout.add( hd );
        // Case langue
        final ListBox langue = new ListBox();
        for ( VersionWeb value : VersionWeb.values() )
        {
            langue.addItem( value.name(), value.getValue() );
        }
        panelAjout.add( langue );

        // Case Ajouter
        Button ajout = new Button( "Ajouter" );
        ajout.addClickHandler( new ClickHandler()
        {

            @Override
            public void onClick( ClickEvent event )
            {
                int row = flexTable.getRowCount();
                SerieWeb newSerie = new SerieWeb( nom.getText(), Integer.parseInt( episode.getText() ), Integer.parseInt( saison.getText() ), VersionWeb.fromValue( langue.getValue( langue
                    .getSelectedIndex() ) ), hd.getValue() );
                newSerie.setActive( true );

                series.add( newSerie );

                addSerie( row, newSerie );

                flexTable.getRowFormatter().setStyleName( row, "flexTableAdded" );
            }
        } );
        ajout.setStyleName( "boutonAjout" );

        // Case Enregistrer
        final Button enregistrer = new Button( "Enregistrer" );
        enregistrer.addClickHandler( new ClickHandler()
        {

            @Override
            public void onClick( ClickEvent event )
            {
                enregistrer.setEnabled( false );
                Collections.sort( series );

                System.out.println( "[MAIN] Call RPC Service setData() for updating" );
                showWaitingScreen();
                helloSeriesWebService.setData( series, new AsyncCallback<Void>()
                {

                    @Override
                    public void onFailure( Throwable caught )
                    {
                        enregistrer.setEnabled( true );
                        hideWaitingScreen();
                        System.out.println( "[MAIN] Call RPC Service setData() failed : " + caught.getMessage() );
                        showError( caught );

                    }

                    @Override
                    public void onSuccess( Void result )
                    {

                        System.out.println( "[MAIN] Call RPC Service setData() Successfull" );
                        refreshFlexTable();
                        hideWaitingScreen();
                        enregistrer.setEnabled( true );
                    }

                } );
            }
        } );
        enregistrer.setStyleName( "boutonEnregistrer" );

        mainPanel.add( panelAjout );
        mainPanel.add( ajout );
        mainPanel.add( enregistrer );
    }

    private void showWaitingScreen()
    {
        waitingPanel.setVisible( true );
    }

    private void hideWaitingScreen()
    {
        waitingPanel.setVisible( false );
    }

    private TextBox createTextBoxEpisode( final SerieWeb serie )
    {
        final TextBox textbox = new TextBox();
        textbox.setText( Integer.toString( serie.getEpisode() ) );

        textbox.addChangeHandler( new ChangeHandler()
        {
            public void onChange( ChangeEvent event )
            {
                if ( isInteger( textbox.getValue() ) )
                {
                    serie.setEpisode( Integer.parseInt( textbox.getValue() ) );
                }
                else
                {
                }
            }

        } );
        return textbox;
    }

    private TextBox createTextBoxSaison( final SerieWeb serie )
    {
        final TextBox textbox = new TextBox();
        textbox.setText( Integer.toString( serie.getSaison() ) );

        textbox.addChangeHandler( new ChangeHandler()
        {
            public void onChange( ChangeEvent event )
            {
                if ( isInteger( textbox.getValue() ) )
                {
                    serie.setSaison( Integer.parseInt( textbox.getValue() ) );
                }
                else
                {
                }
            }

        } );
        return textbox;
    }

    private TextBox createTextBoxNom( final SerieWeb serie )
    {
        final TextBox textbox = new TextBox();
        textbox.setText( serie.getNom() );

        textbox.addChangeHandler( new ChangeHandler()
        {
            public void onChange( ChangeEvent event )
            {
                serie.setNom( textbox.getValue() );
            }

        } );
        return textbox;
    }

    private CheckBox createCheckBoxHd( final SerieWeb serie )
    {
        final CheckBox checkBox = new CheckBox();
        checkBox.setValue( serie.isHd() );

        checkBox.addClickHandler( new ClickHandler()
        {
            @Override
            public void onClick( ClickEvent event )
            {
                serie.setHd( checkBox.getValue() );
            }

        } );
        return checkBox;
    }

    private ListBox createListBoxLangue( final SerieWeb serie )
    {
        final ListBox listBox = new ListBox();

        for ( VersionWeb value : VersionWeb.values() )
        {
            listBox.addItem( value.name(), value.getValue() );
        }
        listBox.setSelectedIndex( serie.getVersion().getIndex() );

        listBox.addChangeHandler( new ChangeHandler()
        {

            public void onChange( ChangeEvent event )
            {
                serie.setVersion( VersionWeb.fromValue( listBox.getValue( listBox.getSelectedIndex() ) ) );
            }

        } );
        return listBox;
    }

    public boolean isInteger( String s )
    {
        boolean isValid = true;
        try
        {
            Integer.parseInt( s );
        }
        catch ( NumberFormatException nfe )
        {
            isValid = false;
        }
        return isValid;
    }

    private void addSerie( int row, final SerieWeb serie )
    {
        // Case Active
        CheckBox active = new CheckBox();
        active.setValue( serie.isActive() );
        flexTable.setWidget( row, 0, active );

        // Case Nom
        TextBox textBox = createTextBoxNom( serie );
        flexTable.setWidget( row, 1, textBox );

        // Case saison
        TextBox saison = createTextBoxSaison( serie );
        flexTable.setWidget( row, 2, saison );

        // Case episode
        TextBox episode = createTextBoxEpisode( serie );
        flexTable.setWidget( row, 3, episode );

        // Case HD
        CheckBox hd = createCheckBoxHd( serie );
        flexTable.setWidget( row, 4, hd );

        // Case langue
        ListBox langue = createListBoxLangue( serie );

        flexTable.setWidget( row, 5, langue );

        // Case Supprimer
        Button supprimer = new Button( "X" );
        supprimer.addClickHandler( new ClickHandler()
        {

            public void onClick( ClickEvent event )
            {
                final int row = series.indexOf( serie );
                series.remove( row );
                flexTable.removeRow( row + 1 );
            }
        } );
        flexTable.setWidget( row, 6, supprimer );
    }

}
